﻿using System;
using System.Web.UI;

using Carbon.Web.Forms.Extensions;
using System.Collections.Generic;

namespace Carbon.Web.Forms.Controls
{
    public abstract class ViewControlBase : Control, IViewControl, IValidator, INamingContainer
    {
        public ViewControlBase()
        {
            this.ClientIDMode = System.Web.UI.ClientIDMode.AutoID;
        }

        #region Fields (8)
        private Binder m_Binder = default(Binder);

        private IEditor m_Editor = default(IEditor);

        private bool m_AutoPostback = default(bool);
        private bool m_Binder_calculated = false;
        private bool m_CanBeNull = true;
        private bool m_IsValid = true;
        private bool m_ReadOnly = default(bool);

        private String m_DataPath = "this";
        #endregion

        #region Properties (8)
        public bool AutoPostback
        {
            get
            {
                return m_AutoPostback;
            }
            set
            {
                m_AutoPostback = value;
            }
        }
        public Binder Binder
        {
            get
            {
                if (!m_Binder_calculated)
                {
                    m_Binder = new Binder(this.GetViewModelContext(), DataPath, true);
                    m_Binder_calculated = true;
                }

                return m_Binder;
            }
        }
        public bool CanBeNull
        {
            get
            {
                return m_CanBeNull;
            }
            set
            {
                m_CanBeNull = value;
            }
        }
        public String DataPath
        {
            get
            {
                return m_DataPath;
            }
            set
            {
                m_DataPath = value;
            }
        }


        protected virtual IEditor Editor
        {
            get
            {
                return m_Editor;
            }
        }
        public bool IsValid
        {
            get
            {
                return m_IsValid;
            }
            set
            {
                m_IsValid = value;
            }
        }

        private ViewControlUpdateState m_PipelineState = default(ViewControlUpdateState);
        public ViewControlUpdateState PipelineState
        {
            get
            {
                return m_PipelineState;
            }
            set
            {
                m_PipelineState = value;
            }
        } 
        protected virtual Object ModelValue
        {
            get
            {
                return Binder.Value;
            }
            set
            {
                Binder.Value = value;
            }
        }
        public bool ReadOnly
        {
            get
            {
                return m_ReadOnly;
            }
            set
            {
                m_ReadOnly = value;
            }
        }
        private String m_CssClass = default(String);
        public String CssClass
        {
            get
            {
                return m_CssClass;
            }
            set
            {
                m_CssClass = value;
            }
        }
        
        private bool m_CreatedViewControls = default(bool);
        protected bool CreatedViewControls
        {
            get
            {
                return m_CreatedViewControls;
            }
            set
            {
                m_CreatedViewControls = value;
            }
        } 
        #endregion

        #region ASP Processing

        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);
            EnsureChildControls();
        }

        #endregion

        #region Methods (6)

        protected abstract IEditor CreateEditor();

        protected override object SaveViewState()
        {
            return ViewControlUpdateState.OnSaveViewState(this, base.SaveViewState);
        }

        protected virtual void CreateViewControls()
        {
            if (CreatedViewControls)
                return;

            this.Controls.Clear();
            m_Editor = CreateEditor();
            if (m_Editor != null)
            {
                this.Controls.Add((Control)m_Editor);
            }

            CreatedViewControls = true;
        }

        protected override bool OnBubbleEvent(object source, EventArgs args)
        {
            if (args is UpdateModelEventArgs)
            {
                OnUpdateModel(source, (UpdateModelEventArgs)args);
            }
            return base.OnBubbleEvent(source, args);
        }

        protected override void LoadViewState(object savedState)
        {
            ViewControlUpdateState.OnLoadViewState(this, savedState, base.LoadViewState);
        }

        public virtual void OnUpdateControl(object sender, UpdateControlEventArgs args)
        {
            m_Binder_calculated = false;

            OnDataBinding(EventArgs.Empty);

            CreateViewControls();

            if (Editor != null)
            {
                Object modelValue = ModelValue;

                if (modelValue is IModelValue)
                    modelValue = ((IModelValue)modelValue).Clone();

                Editor.Value = modelValue;
            }
        }

        public virtual void OnUpdateModel(object sender, UpdateModelEventArgs args)
        {
            m_Binder_calculated = false;

            if (!this.Visible)
                return;

            if (Editor != null)
            {
                Object modelValue = Editor.Value;

                if (modelValue is IModelValue)
                    modelValue = ((IModelValue)modelValue).Clone();

                ModelValue = modelValue;
            }
        }

        protected override void OnPreRender(EventArgs e)
        {
            ViewControlUpdateState.OnPreRender(this, e, base.OnPreRender);
        }

        protected bool CalculateIsValid()
        {
            bool previousIsValid = IsValid;

            try
            {
                Validate();
                return IsValid;
            }
            catch (ApplicationException)
            {
                return false;
            }
            finally
            {
                IsValid = previousIsValid;
            }
        }

        public virtual void Validate()
        {
            if (this.Editor != null)
            {
                if (!CanBeNull)
                {
                    this.IsValid = !this.Editor.IsNull;
                }
                else
                {
                    this.IsValid = true;
                }
            }
            else
            {
                IsValid = true;
            }
        }

        #endregion
    }
}
